package com.zxc.ompz;

import java.io.IOException;
import java.util.Vector;

import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.media.MediaException;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.VolumeControl;

import net.rim.device.api.command.Command;
import net.rim.device.api.command.CommandHandler;
import net.rim.device.api.command.ReadOnlyCommandMetadata;
import net.rim.device.api.system.Characters;
import net.rim.device.api.system.PersistentObject;
import net.rim.device.api.system.PersistentStore;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.util.StringProvider;

/**
 * A class extending the MainScreen class, which provides default standard
 * behavior for BlackBerry GUI applications.
 */
public final class OmpzScreen extends MainScreen 
                              implements MediaStreamPlayerListener{
	private MenuItem menuAddURL;
	private MenuItem menuRemove;
	private MenuItem menuViewLog;
	private MediaField mf;
	private MediaListField mlf;
	
	private Vector mediaVector;
	//private Media currentMedia;
    private MediaStreamPlayer msplayer;
    private VolumeControl volumeControl;
    private int volumeLevel=75;
	private boolean seekOK = true;
	private String dir = "file:///SDCard/Ompz/";
	private String connString = ";deviceside=true;interface=wifi";;
	private long length;
	private long now;
	private long duration;
	private String name;
	private String type;
	/** persist media vector**/
	private PersistentObject po;
	private long key = 0x267d224e6f6d707aL;
	
	public OmpzScreen(){
		po = PersistentStore.getPersistentObject(key);
		mediaVector = loadMedia();
		
		mf = new MediaField();
		mf.setDebug(false);
        this.add(mf);
      
        mlf = new MediaListField(mediaVector);
        mlf.setSize(mediaVector.size());
		this.add(mlf);
		
		menuAddURL = new MenuItem(new StringProvider("Add URL"), 0, 100);
		menuAddURL.setCommand(new Command(new CommandHandler(){
			public void execute(ReadOnlyCommandMetadata metadata, Object context){
				OmpzApp.getTheApp().pushModalScreen(new URLScreen());
			}
		}));
		this.addMenuItem(menuAddURL);
		
		menuRemove = new MenuItem(new StringProvider("Remove"), 0, 100);
		menuRemove.setCommand(new Command(new CommandHandler(){
			public void execute(ReadOnlyCommandMetadata metadata, Object context){
				removeMedia();
			}
		}));
		this.addMenuItem(menuRemove);
		
		menuViewLog = new MenuItem(new StringProvider("View Log"), 0, 100);
		menuViewLog.setCommand(new Command(new CommandHandler() {
			public void execute(ReadOnlyCommandMetadata metadata, Object context){
				viewLog();
			}
		}));
		this.addMenuItem(menuViewLog);
	}
    public void addMedia(Media m){
    	mediaVector.addElement(m);
    	mlf.setSize(mediaVector.size(), mediaVector.size()-1);
    }
    public void removeMedia(){
		if (mlf.isFocus()){
			Media selectedMedia = (Media)mediaVector.elementAt((mlf.getSelectedIndex()));
			Media currentMedia = mlf.getCurrentMedia();
			int choice = Dialog.ask(Dialog.D_YES_NO, "Delete "+selectedMedia.toString()+"?", Dialog.YES);
			if (choice==Dialog.YES){
				if (currentMedia!=null && selectedMedia==currentMedia){
					playerClose();
				}
				mediaVector.removeElementAt(mlf.getSelectedIndex());
				mlf.setSize(mediaVector.size());
			}
		}
    }
    private void setMediaInfo(){
    	if (msplayer!=null && msplayer.getState()>=MediaStreamPlayer.REALIZED){
			name = msplayer.getMediaName();
			type = msplayer.getContentType();
			length = msplayer.getContentLength();
			duration = msplayer.getDuration();
			mf.setMediaName(name);
			mf.setMediaType(type);
			mf.setMediaLength(length);
			mf.setMediaDuration(duration);
			Media m = mlf.getCurrentMedia();
			if (m!=null && !m.isLocal()){
				m.setType(type);
				m.setLength(length);
			}
    	}
    }
    private void playerRealize(Media m){
    	AppLog.log(AppLog.DEBUGING, "OmpzScreen.playerRealize()");
		if (msplayer != null){
			playerClose();
			msplayer=null;
		}
		mf.setEvent("CONNECTING");
		mlf.setCurrentMedia(m);
		seekOK = true;
		if (m.isLocal()){
			String name = m.getName();
			String type = m.getType();
			FileConnection f = null;
			try {
				f = (FileConnection) Connector.open(dir+name, Connector.READ);
				if (!f.exists() || f.fileSize()!=m.getLength()){
					m.setLocal(false);
				}
			}
			catch (IOException e){
				AppLog.log(AppLog.EXCEPTION, e.toString());
				Dialog.alert("Fail to open file!");
				return;
			}
			finally{
				if (f!=null){
					try {
						f.close();
					}
					catch (IOException e) {
						AppLog.log(AppLog.EXCEPTION, e.toString());
						Dialog.alert("Fail to close file!");
						return;
					}
				}
			}
			msplayer = new MediaStreamPlayer(dir+name, type);
			AppLog.log(AppLog.DEBUGING, "REALIZE: new MediaStreamPlayer("+dir+name+","+type+")");
		}
		if (!m.isLocal()){
			String url = m.getUrl();
			msplayer = new MediaStreamPlayer(url+connString, null);
			AppLog.log(AppLog.DEBUGING, "REALIZE: new MediaStreamPlayer("+url+connString+","+"null)");
		}
		msplayer.addMediaStreamPlayerListener(this);
		msplayer.setMediaStreamPlayerLogLevel(AppLog.DEBUGING);
		try {
			msplayer.realize();
		}
		catch (MediaException e) {
			AppLog.log(AppLog.EXCEPTION, e.toString());
			Dialog.alert("Player can not be realized!");
			playerClose();
			return;
		}
		catch (IOException e) {
			AppLog.log(AppLog.EXCEPTION, e.toString());
			Dialog.alert("Connect failed!");
			playerClose();
			return;
		}
		volumeControl = (VolumeControl)msplayer.getControl("VolumeControl");
		if (volumeControl!=null){
			volumeControl.setLevel(volumeLevel);
		}
    }
    private void playerStart() {
		AppLog.log(AppLog.DEBUGING, "OmpzScreen.playerStart()");
		if (msplayer!=null){
			try { 
				msplayer.start();
			}
			catch (Exception e) {
				AppLog.log(AppLog.EXCEPTION, e.toString());
				return;
			}
			mf.setPause(false);
			mf.setEvent("PLAY");
		}
	}
    private void playerStop(){
		AppLog.log(AppLog.DEBUGING, "OmpzScreen.playerStop()");
		if (msplayer != null){
			try {
				msplayer.stop();
			}
			catch (MediaException e){
				AppLog.log(AppLog.EXCEPTION, e.toString());
				return;
			}
			mf.setPause(true);
			mf.setEvent("PAUSE");
		}
	}
    private void playerClose(){
		AppLog.log(AppLog.DEBUGING, "OmpzScreen.playerClose()");
		if(msplayer != null) {
			msplayer.removeMediaStreamPlayerListener(null);
			try {
				msplayer.close();
			}
			catch (MediaException e) {
				AppLog.log(AppLog.EXCEPTION, e.toString());
				return;
			}
			finally{
				msplayer=null;
				mlf.setCurrentMedia(null);
				mf.setEvent("CLOSED");
			}
		}
		AppLog.log(AppLog.DEBUGING, "PLAYER: CLOSED");
	}
    private void playerUnavailable(){
    	AppLog.log(AppLog.DEBUGING, "playerUnavailable()");
    	if(msplayer != null) {
    		msplayer.deallocate();
    		mf.setEvent("UNAVAILABLE");
    	}
    }
    private void playerAvailable(){
    	AppLog.log(AppLog.DEBUGING, "playerAvailable()");
    	if(msplayer != null) {
    		try {
				msplayer.prefetch();
			}
    		catch (MediaException e) {
    			AppLog.log(AppLog.EXCEPTION, e.toString());
			}
    		catch (IOException e) {
    			AppLog.log(AppLog.EXCEPTION, e.toString());
			}
    		mf.setEvent("AVAILABLE");
    	}
    }
	private void saveMedia(){
		synchronized(po){
			po.setContents(mediaVector);
			po.commit();
		}
	}
	private Vector loadMedia(){
		Vector v;
		synchronized(po){
			v = (Vector) po.getContents();
		}
		return v==null? new Vector(): v;
	}
	/**
	 * display the log screen 
	 * 
	 * */
	public void viewLog(){
		OmpzApp.getTheApp().pushScreen(OmpzApp.getLogScreen());
	}
	/**
	 * application exit
	 */
	public boolean onClose() {
		AppLog.log(AppLog.DEBUGING, "OmpzScreen.onClose()");
		playerClose();
		saveMedia();
		//OmpzApp.getLogScreen().close();
		return super.onClose();
	}
	protected boolean navigationClick(int status, int time) {
		if (mlf.isFocus()){
			int index = mlf.getSelectedIndex();
			Media selectedMedia = (Media)mediaVector.elementAt(index);
			Media currentMedia = mlf.getCurrentMedia();
			if (currentMedia==null || selectedMedia!=currentMedia){
				playerRealize(selectedMedia);
				mlf.setCurrentMedia(selectedMedia);
				setMediaInfo();
				playerStart();
			}
		}
		return true;
	}
	
	/************************* KeyListener Begin *************************/
	protected boolean keyChar(char key, int status, int time){
		AppLog.log(AppLog.DEBUGING, "keyChar()="+key);
		switch (key){
		case Characters.SPACE:
			keyEvent("PlayOrPause", 0);
			break;
		case Characters.LATIN_SMALL_LETTER_Q:
		case Characters.LATIN_SMALL_LETTER_W:
		case Characters.LATIN_SMALL_LETTER_E:
		case Characters.LATIN_SMALL_LETTER_R:
		case Characters.LATIN_SMALL_LETTER_T:
		case Characters.LATIN_SMALL_LETTER_A:
		case Characters.LATIN_SMALL_LETTER_S:
		case Characters.LATIN_SMALL_LETTER_D:
		case Characters.LATIN_SMALL_LETTER_F:
		case Characters.LATIN_SMALL_LETTER_G:
		case Characters.LATIN_SMALL_LETTER_Z:
		case Characters.LATIN_SMALL_LETTER_X:
		case Characters.LATIN_SMALL_LETTER_C:
		case Characters.LATIN_SMALL_LETTER_V:
			keyEvent("Backward", 0);
			break;
		case Characters.LATIN_SMALL_LETTER_Y:
		case Characters.LATIN_SMALL_LETTER_U:
		case Characters.LATIN_SMALL_LETTER_I:
		case Characters.LATIN_SMALL_LETTER_O:
		case Characters.LATIN_SMALL_LETTER_P:
		case Characters.LATIN_SMALL_LETTER_H:
		case Characters.LATIN_SMALL_LETTER_J:
		case Characters.LATIN_SMALL_LETTER_K:
		case Characters.LATIN_SMALL_LETTER_L:
		case Characters.LATIN_SMALL_LETTER_B:
		case Characters.LATIN_SMALL_LETTER_N:
		case Characters.LATIN_SMALL_LETTER_M:
			keyEvent("Forward", 0);
			break;
		case Characters.DELETE:
		case Characters.BACKSPACE:
			keyEvent("Delete", 0);
			return true;
		}
		return false;
	}
	protected boolean keyControl(char key, int status, int time) {
		switch (key){
		case Characters.CONTROL_VOLUME_UP:
			keyEvent("VolumeUp", 0);
			return true;
		case Characters.CONTROL_VOLUME_DOWN:
			keyEvent("VolumeDown", 0);
			return true;
		default:
			return super.keyCharUnhandled(key, status, time);
		}
	}
	private void keyEvent(String event, int context) {
    	if (event.equalsIgnoreCase("PlayOrPause") && msplayer!=null){
        	if (msplayer.getState()==MediaStreamPlayer.STARTED) {
        		AppLog.log(AppLog.DEBUGING, "USER PAUSE");
        		playerStop();
        	}
        	else {
        		AppLog.log(AppLog.DEBUGING, "USER PAUSE");
        		playerStart();
        	}
    	}
    	else if (event.equalsIgnoreCase("Backward")){
    		if (seekOK){
    			AppLog.log(AppLog.DEBUGING, "USER SEEK: backward 5s");
    			seekOK = false;
    			long where = 0;
    			if (msplayer != null) {
    				try	{
    					where = msplayer.getMediaTime()-5000000;
    					now = msplayer.setMediaTime(where);
    					mf.setTimer(now);
    				}
    				catch (Exception e) {
    					AppLog.log(AppLog.EXCEPTION, e.toString());
    				}   			
    			}
    			AppLog.log(AppLog.DEBUGING, "USER SEEK: setMediaTime(" + where + ")=" + now);
    		}
    		else{
    			AppLog.log(AppLog.DEBUGING, "USER SEEK: last seek not complete");
    		}
    	}
    	else if (event.equalsIgnoreCase("Forward")){
    		if (seekOK){
    			AppLog.log(AppLog.DEBUGING, "USER SEEK: forward 5s");
    			seekOK = false;
    			long where = 0;
    			if (msplayer != null) {
    				try	{
    					where = msplayer.getMediaTime()+5000000;
    					now = msplayer.setMediaTime(where);
    					mf.setTimer(now);
    				}
    				catch (Exception e) {
    					AppLog.log(AppLog.EXCEPTION, e.toString());
    				}   			
    			}
    			AppLog.log(AppLog.DEBUGING, "USER SEEK: setMediaTime(" + where + ")=" + now);
    		}
    		else{
    			AppLog.log(AppLog.DEBUGING, "USER SEEK: last seek not complete");
    		}
    	}
    	else if(event.equalsIgnoreCase("Delete")){
    		removeMedia();
    	}
    	else if (event.equalsIgnoreCase("VolumeUp")){
    		AppLog.log(AppLog.DEBUGING, "USER CONTROL: Volume Up");
    		volumeLevel += 5;
    		if (volumeLevel>100){
    			volumeLevel=100;
    		}
    		if (volumeControl!=null){
    			volumeControl.setLevel(volumeLevel);
    		}
    		mf.setVolumeLevel(volumeLevel);
    	}
    	else if (event.equalsIgnoreCase("VolumeDown")){
    		AppLog.log(AppLog.DEBUGING, "USER CONTROL: Volume Down");
    		volumeLevel -= 5;
    		if (volumeLevel<0){
    			volumeLevel=0;
    		}
    		if (volumeControl!=null){
    			volumeControl.setLevel(volumeLevel);
    		}
    		mf.setVolumeLevel(volumeLevel);
    	}
    }
	/************************* KeyListener End *************************/
	
	
	/************************* MediaStreamPlayerListener *************************/
	public void playerLog(int level, String msg) {
		AppLog.log(level, msg);
	}
	public void playerUpdate(String event, Object eventData) {
		if(event.equalsIgnoreCase(PlayerListener.END_OF_MEDIA)) {
			AppLog.log(AppLog.DEBUGING, "EVENT: END OF MEDIA");
			playerClose();
		}
		else if(event.equalsIgnoreCase(PlayerListener.DEVICE_UNAVAILABLE)){
			AppLog.log(AppLog.DEBUGING, "EVENT: " + event +"["+ eventData +"]");
			playerUnavailable();
		}
		else if(event.equalsIgnoreCase(PlayerListener.DEVICE_AVAILABLE)){
			AppLog.log(AppLog.DEBUGING, "EVENT: " + event +"["+ eventData +"]");
			playerAvailable();
		}
		else if(event.equalsIgnoreCase(PlayerListener.DURATION_UPDATED)){
			AppLog.log(AppLog.DEBUGING, "EVENT: " + event +"["+ eventData +"]");
			duration = ((Long)eventData).longValue();
			mf.setMediaDuration(duration);
		}
		else if(event.equalsIgnoreCase(MediaStreamPlayerListener.USER_SEEK_OK)){
			AppLog.log(AppLog.DEBUGING, "EVENT: USER_SEEK_OK");
			seekOK = true;
		}
		else if(event.equalsIgnoreCase(MediaStreamPlayerListener.DOWNLOAD_OK)){
			AppLog.log(AppLog.DEBUGING, "EVENT: DOWNLOAD_OK");
			mlf.getCurrentMedia().setLocal(true);
			mlf.update();
		}
		else if(event.equalsIgnoreCase(MediaStreamPlayerListener.BUFFER_FULL)){
			return;
		}
		else if(event.equalsIgnoreCase(MediaStreamPlayerListener.BUFFER_EMPTY)){
			return;
		}
		else if(event.equalsIgnoreCase(MediaStreamPlayerListener.CONNECTION_OPEN)){
			return;
		}
		else if(event.equalsIgnoreCase(MediaStreamPlayerListener.CONNECTION_CLOSE)){
			return;
		}
	}
	public void contentLengthUpdated(long contentLength) {
		length = contentLength;
		mf.setMediaLength(length);
		mlf.getCurrentMedia().setLength(contentLength);
	}
	public void updatePlayingPosition(long now) {
		this.now = now;
		mf.setTimer(now);
	}
	public void updateBufferPosition(long[] positions) {
		mf.setBuffer(positions);
	}
	/************************* MediaStreamPlayerListener End *************************/
}
